package com.yesep.learn.design.behavioral.chain_of_responsibility;

import com.yesep.learn.design.behavioral.chain_of_responsibility.engine.*;
import com.yesep.learn.design.behavioral.chain_of_responsibility.impl.leave.*;

import java.time.*;

/**
 * Chain of Responsibility（职责链）设计模式是一种行为型设计模式，它通过将请求沿着一个处理者链传递，使得链中的每个处理者都有机会处理该请求，直到有一个处理者处理它为止。
 * 这种设计模式的主要目的是将请求的发送者和接收者解耦，从而降低系统各部分的耦合度，提高系统的灵活性和可扩展性。
 * <p>
 * 一、定义与概述
 * Chain of Responsibility 设计模式定义了一系列的处理者（Handler），它们按照一定顺序排列，每个处理者都负责处理特定的请求，或者将请求传递给链中的下一个处理者。
 * 当请求发生时，它会沿着这条链传递，直到有一个处理者能够处理它为止。
 * <p>
 * 二、结构分析
 * Chain of Responsibility 设计模式主要包含以下几个角色：
 * <p>
 * 抽象处理者（Handler）：定义了一个处理请求的接口，通常包含一个指向下一个处理者的引用（可选），以及一个处理请求的方法。
 * 具体处理者（Concrete Handler）：实现了抽象处理者的接口，具体处理请求的逻辑。如果当前处理者能够处理请求，则处理它；否则，将请求传递给链中的下一个处理者。
 * 客户端（Client）：创建处理者链，并向链的第一个处理者发送请求。客户端不需要知道请求是如何被处理的，也不需要知道链的具体结构。
 * 三、优缺点
 * 优点
 * 解耦：将请求的发送者和接收者解耦，降低了系统各部分的耦合度。
 * 灵活性：可以动态地重新组织职责链，以满足不同的需求。
 * 可扩展性：可以轻松地增加新的处理者，而不需要修改现有的代码。
 * 易于维护：每个处理者只关注自己的处理逻辑，使得系统更加易于维护。
 * 缺点
 * 性能问题：由于请求会沿着链传递，因此可能会影响系统的性能。
 * 复杂性增加：如果链过长或者处理逻辑过于复杂，可能会增加系统的复杂度。
 * 请求可能得不到处理：如果链中的处理者都不能处理请求，那么请求可能会一直传递到链的末端而得不到处理。
 * 四、应用场景
 * Chain of Responsibility 设计模式适用于以下场景：
 * <p>
 * 多个对象可以处理同一请求：当系统中有多个对象可以处理同一请求时，可以使用职责链模式来动态地决定由哪个对象处理该请求。
 * 请求的处理顺序不确定：当请求的处理顺序需要根据运行时的情况动态决定时，可以使用职责链模式来灵活地调整处理顺序。
 * 需要动态地增加或删除处理者：当系统需要动态地增加或删除处理者时，可以使用职责链模式来轻松地实现这一需求。
 * 五、实现方式
 * Chain of Responsibility 设计模式可以通过多种方式实现，包括基于接口的实现、基于抽象类的实现、基于匿名内部类的实现以及基于Lambda表达式的实现等。
 * 具体实现方式可以根据项目的需求和团队的偏好来选择。
 * <p>
 * 六、注意事项
 * 在实现 Chain of Responsibility 设计模式时，需要注意以下几点：
 * <p>
 * 避免循环调用：确保链中的处理者之间不会出现循环调用，以防止形成死循环。
 * 确定链的顶端和底端：明确链的起始和结束位置，以确保请求能够被正确地传递和处理。
 * 控制链的长度：根据实际需求合理控制链的长度，避免过长或过短的链对系统性能造成不利影响。
 * 处理异常情况：在处理请求时，要考虑到可能出现的异常情况，并给出相应的处理措施。
 */
public class Main {
    public static void main(String[] args) {
        LocalDateTime begin = LocalDateTime.of(2024, 8, 3, 12, 0);
        LocalDateTime end = begin.plusDays(6);
        end = end.plusHours(12);
        ChainPayload user = new ChainPayload();
        user.setUserId("001");
        user.setUserName("汪汪");
        user.setUserRole("Employee");
        //构建责任链
        LeaveRequest leaveRequest = new LeaveRequest(user, begin, end);
        LeaveChainBuilder builder = new LeaveChainBuilder(leaveRequest);
        //责任链运行上下文
        ChainContext<LeaveRequest> context = new ChainContext<>(builder, user);
        //1、请假人向组长启动请假
        context.getCurrentHandler().startup(context);
        System.out.println(context.getCurrentHandler());
        //2、组长审批
        ChainPayload teamLeader = new ChainPayload();
        teamLeader.setUserId("002");
        teamLeader.setUserName("组长");
        teamLeader.setUserRole("TeamLeader");
        teamLeader.setComment("不同意，请补充理由");
        context.setPayload(teamLeader);
        //不同意，退回
        context.getCurrentHandler().backward(context);
        //申请人重新修改
        System.out.println(context.getCurrentHandler());
        user.setComment("下雨了");
        context.setPayload(user);
        context.getCurrentHandler().forward(context);

        //不同意，退回
        System.out.println(context.getCurrentHandler());
        teamLeader.setComment("理由不充分");
        context.setPayload(teamLeader);
        context.jump(LeaveStartHandler.class.getName());//不能直接更改
        //申请人重新修改
        System.out.println(context.getCurrentHandler());
        user.setComment("下雨了，回去收衣服");
        context.setPayload(user);
        context.getCurrentHandler().forward(context);

        //组长同意
        System.out.println(context.getCurrentHandler());
        teamLeader.setComment("同意");
        context.setPayload(teamLeader);
        context.getCurrentHandler().forward(context);
        //3、部门经理向总经理提交请假
        System.out.println(context.getCurrentHandler());
        ChainPayload departmentManager = new ChainPayload();
        departmentManager.setUserId("003");
        departmentManager.setUserName("部门经理");
        departmentManager.setUserRole("DepartmentManager");
        departmentManager.setComment("同意");
        context.setPayload(departmentManager);
        context.getCurrentHandler().forward(context);
        //4、总经理处理：不同意
        System.out.println(context.getCurrentHandler());
        context.setPayload(departmentManager);
        ChainPayload generalManager = new ChainPayload();
        generalManager.setUserId("004");
        generalManager.setUserName("总经理");
        generalManager.setUserRole("GeneralManager");

        generalManager.setComment("同意");
        context.setPayload(generalManager);
        context.getCurrentHandler().forward(context);

        System.out.println(context.getCurrentHandler());
    }
}
